#include "tunnel_mainwindow.h"
#include "ui_tunnel_mainwindow.h"
#include <time.h>
#include <QtGui/QMessageBox>


void addFriendToList(QStandardItemModel *model, const QString nickName, bool online, const QString status)
{
    model->insertRow(0);
    model->setData(model->index(0, 0), nickName);
    model->setData(model->index(0, 1), status);
}

Tunnel_MainWindow::Tunnel_MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::Tunnel_MainWindow)
{
    ui->setupUi(this);

    // External dialogs and frames
    addFriendDialog = new AddFriendDialog(this);
    connect( addFriendDialog, SIGNAL(addNewFriend(QString,QString)), this, SLOT(addNewFriend(QString,QString)));


    socket = new ClientSocket(this);

    // Connect Socket with the GUI.
    connect( socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)) );
    connect( socket, SIGNAL(disconnected()), this, SLOT(on_socketDisconnected()) );
    connect( socket, SIGNAL(cSocketError(QString)), this, SLOT(on_cSocketError(QString)) );
    connect( socket, SIGNAL(changeLoginStatus(const int, const QString&)), this, SLOT(on_changeLoginStatus(const int, const QString&)) );

    // Connect Chathandler with GUI
    connect( socket->getChatHandler(), SIGNAL(newMessage(const QString&, QString&)), this, SLOT(on_newMessage(const QString&, QString&)) );
    connect( socket->getChatHandler(), SIGNAL(cError(const QString&)), this, SLOT(on_cSocketError(const QString&)) );
    connect( socket->getChatHandler(), SIGNAL(updateFriendlist(QString)), this, SLOT(on_updateFriendlist(QString)));
    connect( socket->getChatHandler(), SIGNAL(incommingFriendrequest(QString)), this, SLOT(on_incommingFriendrequest(QString)) );

    // Other connections
    connect( ui->lePasswort, SIGNAL(returnPressed()), this, SLOT(on_lePasswort_returnPressed()) );
    connect( ui->leBenutzername, SIGNAL(returnPressed()), this, SLOT(on_lePasswort_returnPressed()) );
    connect( ui->teMessage, SIGNAL(returnWithoutShiftPressed()), this, SLOT(on_teMessage_returnWithoutShiftPressed()) );

    // Friendlist
    friendlistItemModel = new QStandardItemModel(0, 2, ui->lvFriends);
    friendlistItemModel->setHeaderData(0, Qt::Horizontal, tr("Name"));
    friendlistItemModel->setHeaderData(1, Qt::Horizontal, tr("Status"));

    ui->lvFriends->setModel(friendlistItemModel);
}

Tunnel_MainWindow::~Tunnel_MainWindow()
{
    if(socket)
        delete socket;

    delete addFriendDialog;
    delete ui;
}

void Tunnel_MainWindow::on_pbLogin_clicked()
{
    QString error = "";
    if(ui->leBenutzername->text() == "")
        error += "Please enter a valid username!\n";

    if(ui->lePasswort->text() == "")
        error += "Please enter a valid password!\n";

    if( error != "" )
    {
        QMessageBox::information(this, tr("Tunnel"), error);
        return;
    }

    // Setup login information, password should be encryptet in future!
    socket->setLoginInformation(ui->leBenutzername->text().toStdString().c_str(),
                                ui->lePasswort->text().toStdString().c_str());

    // Abort current connection
    socket->abort();

    // Reconnect
    socket->connectToHost("127.0.0.1", 9001);
}

void Tunnel_MainWindow::displayError(QAbstractSocket::SocketError socketError)
{
    switch (socketError) {
    case QAbstractSocket::RemoteHostClosedError:
        break;
    case QAbstractSocket::HostNotFoundError:
        QMessageBox::information(this, tr("Tunnel"),
                                 tr("Could not find host, verify that you are connected to the internet!"));
        break;
    case QAbstractSocket::ConnectionRefusedError:
        QMessageBox::information(this, tr("Tunnel"),
                                 tr("Connection to Tunnel Server failed! Please try again later."));
        break;
    default:
        QMessageBox::information(this, tr("Tunnel"),
                                 tr("The following error occurred: %1.")
                                 .arg(socket->errorString()));
    }
}

void Tunnel_MainWindow::on_socketDisconnected()
{
    // Remove friends from friendlist
    friendlistItemModel->removeRows(0, friendlistItemModel->rowCount());
}

void Tunnel_MainWindow::on_newMessage(const QString &from, QString &message)
{
    time_t t;
    struct tm *ts;

    t = time(NULL);
    ts = localtime(&t);
    
    message.sprintf( "[%s%d:%s%d] %s: %s", (ts->tm_hour < 10 ? "0" : ""), ts->tm_hour,
                                           (ts->tm_min < 10 ? "0" : ""), ts->tm_min,
                                           from.toStdString().c_str(),
                                           message.toStdString().c_str() );
    
    ui->tbChat->appendPlainText(message);
}

void Tunnel_MainWindow::on_cSocketError(const QString &error)
{
    QMessageBox::information(this, tr("Tunnel"), error);
}

void Tunnel_MainWindow::on_pbSenden_clicked()
{
    Package package;

    setupMessagePackage(&package, ui->teMessage->toPlainText());
    socket->sendPackage(&package);

    ui->teMessage->setPlainText("");
}

void Tunnel_MainWindow::on_teMessage_returnWithoutShiftPressed()
{
    on_pbSenden_clicked();
}

void Tunnel_MainWindow::on_action_Beenden_activated()
{
    close();
}

void Tunnel_MainWindow::on_leBenutzername_returnPressed()
{
    on_pbLogin_clicked();
}

void Tunnel_MainWindow::on_lePasswort_returnPressed()
{
    on_pbLogin_clicked();
}

void Tunnel_MainWindow::on_updateFriendlist(QString sFriendlist)
{
    // Remove friends from friendlist
    friendlistItemModel->removeRows(0, friendlistItemModel->rowCount());

    while( sFriendlist.length() > 1 )
    {
        // Extracting friends data from incomming friendlist
        QString myFriend  = sFriendlist.left( sFriendlist.indexOf(';') );

        QString loginName = myFriend.left( myFriend.indexOf(':') ); // Should popup as tooltip, unused up to now

        QString nickName  = myFriend.mid( myFriend.indexOf(':') + 1,
                                          myFriend.indexOf(':', myFriend.indexOf(':')) );

        QString status    = myFriend.mid( myFriend.indexOf(':', myFriend.indexOf(':') + 1) + 1 );
        bool online       = ( status == "online" ? true : false );

        // Remove friends data from incomming friendlist
        sFriendlist = sFriendlist.right( sFriendlist.length() - sFriendlist.indexOf(';') - 1 );

        addFriendToList(friendlistItemModel, nickName, online, status);
    }
}

void Tunnel_MainWindow::on_pbNewFriend_clicked()
{
    addFriendDialog->show();
}

void Tunnel_MainWindow::addNewFriend(const QString &friend_loginName, const QString &rMessage)
{
    Package package;
    setupSystemPackage(&package, TUNNEL_COMMANDCATEGORY_FRIENDS, TUNNEL_COMMAND_ADDFRIEND, friend_loginName + ":" + rMessage);
    socket->sendPackage(&package);

    QMessageBox::information(this, tr("Tunnel"),
                             tr("Your friendship request was sended to %1.").arg(friend_loginName));
}

void Tunnel_MainWindow::on_incommingFriendrequest(QString sFriendrequests)
{
    while( sFriendrequests.length() > 1 )
    {
        // Extracting friends data from incomming friendlist
        QString friendrequest  = sFriendrequests.left( sFriendrequests.indexOf(';') );

        quint32 uid       = friendrequest.left( friendrequest.indexOf(':') ).toULongLong(); // Should popup as tooltip, unused up to now

        QString nickName  = friendrequest.mid( friendrequest.indexOf(':') + 1,
                                               friendrequest.indexOf(':', friendrequest.indexOf(':') + 1) - 2 );

        QString rMessage  = friendrequest.mid( friendrequest.indexOf(':', friendrequest.indexOf(':') + 1) + 1 );

        // Remove friends data from incomming friendlist
        sFriendrequests = sFriendrequests.right( sFriendrequests.length() - sFriendrequests.indexOf(';') - 1 );

        // Create a new window for this request.
        friendRequests.resize(friendRequests.size() + 1);
        friendRequests.at(friendRequests.size() - 1) = new FriendInventationDialog(uid, nickName, rMessage, this);
        connect( friendRequests.at(friendRequests.size() - 1), SIGNAL(acceptFriendInventation(const quint32&)), this, SLOT(acceptFriendInventation(const quint32&)) );
        friendRequests.at(friendRequests.size() - 1)->show();
    }
}

void Tunnel_MainWindow::acceptFriendInventation(const quint32 &applicant_uid)
{
    QString arguments;
    arguments.sprintf("%d", applicant_uid);
    Package package;
    setupSystemPackage(&package, TUNNEL_COMMANDCATEGORY_FRIENDS, TUNNEL_COMMAND_ACCEPTFRIENDINVENTATION, arguments);
    socket->sendPackage(&package);

    // Refresh friendlist
    Package friendlistPackage;
    setupSystemPackage(&friendlistPackage, TUNNEL_COMMANDCATEGORY_FRIENDS, TUNNEL_COMMAND_UPDATEFRIENDLIST);
    socket->sendPackage(&friendlistPackage);
}

void Tunnel_MainWindow::on_changeLoginStatus(int progress, const QString &status)
{
    ui->pbarStatus->setValue(progress);
    ui->lStatus->setText(status);
}
